import com.example.demo.http.servlet.MyRequest;
import com.example.demo.http.servlet.MyResponse;
import com.example.demo.http.servlet.MyServlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;

public class HttpServer {

    private static final int DEFAULT_PORT = 8080;
    private Map<String, MyServlet> urlPattern = new HashMap<>();
    private int port;
    private ServerSocket serverSocket;
    private Properties webProp = new Properties();

    public HttpServer(int port) throws IOException {
        this.port = port;
    }

    private void init() {
        try {
            InputStream resource = HttpServer.class.getClassLoader().getResourceAsStream("web.properties");
            Objects.requireNonNull(resource, "web.properties need be configuration ... ");
            webProp.load(resource);
            Enumeration<String> enumeration = (Enumeration<String>) webProp.propertyNames();
            while (enumeration.hasMoreElements()) {
                String key = enumeration.nextElement();
                String clazz = webProp.getProperty(key);
                Class<?> clazzObj = Class.forName(clazz);
                if (!MyServlet.class.isAssignableFrom(clazzObj)) {
                    continue;
                }
                try {
                    Constructor<?> constructor = clazzObj.getConstructor();
                    MyServlet obj = (MyServlet) constructor.newInstance();
                    urlPattern.put(key, obj);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {

        HttpServer httpServer = new HttpServer(DEFAULT_PORT);
        httpServer.init();
        httpServer.start();
    }

    private void start() {
        try {
            serverSocket = new ServerSocket(port);
            System.out.println("start server at port: " + port);
            while (true) {
                Socket socket = serverSocket.accept();
                InputStream is = socket.getInputStream();
                OutputStream os = socket.getOutputStream();
                MyRequest request = new MyRequest(is);
                MyResponse response = new MyResponse(os);
                String uri = request.getUri();
                boolean hasUrl = false;
                for (Map.Entry<String, MyServlet> entry : urlPattern.entrySet()) {
                    String url = entry.getKey();
                    if (request.getUri().matches(url)) {
                        MyServlet myServlet = urlPattern.get(uri);
                        myServlet.service(request, response);
                        hasUrl = true;
                        break;
                    }
                }
                if (!hasUrl) {
                    response.write("404 Page Not Found ...");
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
